#include "Log/Logger.h"
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

// 构造函数私有化
Logger::Logger(const std::string &baseFilename, LogLevel level):
    logLevel(level), 
    baseFilename(baseFilename)
{
    if(!checkDir())
    {
        running.store(false);
        return;
    }
    running.store(true);
    openLogFile(); // 打开日志文件
    // 启动日志写入线程
    logThread = std::thread(&Logger::processLog, this);
}

Logger::~Logger()
{
    // 停止日志写入线程
    running.store(false);
    cv.notify_all(); // 唤醒线程
    if (logThread.joinable())
    {
        logThread.join();
    }

    // 关闭日志文件
    if (logFile.is_open())
    {
        logFile.close();
    }
}

std::string Logger::getCurrentTime()
{
    auto now = std::chrono::system_clock::now();
    auto time = std::chrono::system_clock::to_time_t(now);
    auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;

    std::tm tm_time = *std::localtime(&time);

    std::ostringstream oss;
    oss << std::put_time(&tm_time, "%Y-%m-%d %H:%M:%S")
        << "." << std::setw(3) << std::setfill('0') << ms.count();

    return oss.str();
}

std::string Logger::getCurrentDate()
{
    auto now = std::time(nullptr);
    auto tm = *std::localtime(&now);
    std::ostringstream oss;
    oss << std::put_time(&tm, "%Y-%m-%d");
    return oss.str();
}

std::string Logger::levelToString(LogLevel level)
{
    switch (level)
    {
    case DEBUG:
        return "DEBUG";
    case INFO:
        return "INFO";
    case WARN:
        return "WARN";
    case ERROR:
        return "ERROR";
    default:
        return "UNKNOWN";
    }
}

void Logger::openLogFile()
{
    currentDate = getCurrentDate();
    std::string filename = strBaseDir + "/" + baseFilename + "_" + currentDate + ".log";
    logFile.open(filename, std::ios::out | std::ios::app);
    if (!logFile.is_open())
    {
        throw std::runtime_error("Failed to open log file: " + filename);
    }
}

void Logger::checkLogFile()
{
    std::string today = getCurrentDate();
    if (today != currentDate)
    {
        logFile.close();
        openLogFile(); // 重新打开新的日志文件
    }
}

void Logger::log(LogLevel level, const std::string &message)
{
    if (level < logLevel)
    {
        return;
    }

    std::string logEntry = "[" + getCurrentTime() + "] [" + levelToString(level) + "] " + message;

    // 将日志消息加入队列
    {
        std::lock_guard<std::mutex> lock(queueMutex);
        logQueue.push(logEntry);
    }

    // 通知日志写入线程
    cv.notify_one();
}

void Logger::processLog()
{
    while (running.load() || !logQueue.empty())
    {
        std::unique_lock<std::mutex> lock(queueMutex);

        // 等待队列中有日志消息
        cv.wait(lock, [this]()
                { return !logQueue.empty() || !running.load(); });

        // 将队列中的所有日志消息写入文件
        while (!logQueue.empty())
        {
            std::string logEntry = logQueue.front();
            logQueue.pop();

            lock.unlock(); // 释放锁，允许其他线程继续添加日志

            // 写入日志文件
            {
                std::lock_guard<std::mutex> logLock(logMutex);
                checkLogFile(); // 检查是否需要切换日志文件
                if (logFile.is_open())
                {
                    logFile << logEntry << std::endl;
                }
                else
                {
                    std::cerr << "Log file is not open!" << std::endl;
                }
            }

            lock.lock(); // 重新加锁，继续处理队列
        }
    }
}

// 获取单例实例
Logger &Logger::getInstance(const std::string &baseFilename, LogLevel level)
{
    static Logger instance(baseFilename, level);
    return instance;
}

void Logger::setLogLevel(LogLevel level)
{
    logLevel = level;
}

void Logger::debug(const std::string &message)
{
    log(DEBUG, message);
}

void Logger::info(const std::string &message)
{
    log(INFO, message);
}

void Logger::warn(const std::string &message)
{
    log(WARN, message);
}

void Logger::error(const std::string &message)
{
    log(ERROR, message);
}

bool Logger::checkDir()
{
    char path[128];
    ssize_t len = readlink("/proc/self/exe", path, sizeof(path) - 1);
    if (len != -1)
    {
        path[len] = '\0';
        std::string dir = std::string(path);
        size_t lastSlash = dir.find_last_of('/');
        if (lastSlash != std::string::npos)
        {
            dir = dir.substr(0, lastSlash); // 提取目录路径
        }
        strBaseDir = dir + "/Log";
    }
    struct stat info;
    std::cout << strBaseDir << std::endl;
    if (!(stat(strBaseDir.c_str(), &info) == 0 && (info.st_mode & S_IFDIR)))
    {
        std::cout << "create dir suc" << std::endl;
        if (mkdir(strBaseDir.c_str(), 0777) == 0)
        {
            return true;
        }
    }
    else
    {
        std::cout << "dir already exits..." << std::endl;
        return true;
    }
    return false;
}
